package com.mingqijia.gassafety.webserver.webSocket;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.mingqijia.gassafety.db.entity.Organization;
import com.mingqijia.gassafety.shared.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @author zhangfei
 * @version 1.0.0
 * @ClassName WebSocketProcess.java
 * @Description webSocket 消息，持不同客户端消息区分
 * @createTime 2022年06月13日
 */
@Slf4j
@Controller
@ServerEndpoint(value = "/webSocket/notify/{spId}/{t}")
public class WebSocketProcess {


    private static final String sepa=";";

    private static ConcurrentHashMap<String, ConcurrentHashMap<String,WebSocketProcess>> concurrentHashMap
            = new ConcurrentHashMap<>(12);
    private RedisTopicSendTemplate redisTopicSendTemplate = SpringUtil.getBean(RedisTopicSendTemplate.class);
    /**
     * 会话对象
     **/
    private Session session;


    @OnOpen
    public void onOpen(Session session,@PathParam("spId")String spId,
                       @PathParam("t")String t) {
        //每新建立一个连接，spId为key,this为value存储到map中
        this.session = session;
        ConcurrentHashMap<String, WebSocketProcess> hashMap = new ConcurrentHashMap<>();
        if (concurrentHashMap.get(spId)!=null&&concurrentHashMap.get(spId).keySet().size()>0){
            hashMap = concurrentHashMap.get(spId);
        }
        hashMap.put(spId+sepa+t, this);
        concurrentHashMap.put(spId, hashMap);
        log.info("WebSocketProcess: Open a websocket. id={}", spId);
    }


    @OnClose
    public void onClose(Session session,@PathParam("spId")String spId
    , @PathParam("t")String t) {
        //客户端连接关闭时，移除map中存储的键值对
        String key =spId +sepa+t;
        ConcurrentHashMap<String, WebSocketProcess> con = concurrentHashMap.get(spId);
        if (con!=null&&con.keySet().size()>0) {
            con.remove(key);
        }
        log.info("WebSocketProcess: close a websocket, 当前关闭回话客户端spId= {}", spId);
    }

    /**
     * 接收到客户端消息时触发
     */
    @OnMessage
    public void onMessage(String message,@PathParam("spId") String spId) {
        log.info("webSocketProcess-onMessage：WebSocketProcess={}"
                ,JSONObject.toJSONString(concurrentHashMap));
        log.info("WebSocketProcess: 接收消息来自客户端client spId={},msg={}", spId, message);
    }

    /**
     * 连接发生异常时候触发
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocketProcess：Error websocket:{} ", error);
    }

    /**
     * 根据spid区分客户端消息
     *
     * @param spId
     * @param message
     */
    public static void sendMessage(String spId, String message, List<Organization> organizations){
        log.info("本地消息通知：spId={},message={},organizations={}",spId,message,organizations);
        //根据spId,从map中获取存储的webSocket对象
        log.info("webSocketProcess-sendMessage：WebSocketProcess={}"
                ,JSONObject.toJSONString(concurrentHashMap));
        ConcurrentHashMap<String, WebSocketProcess> concurrentMapParents=new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(organizations)){
            for (int i = 0; i < organizations.size(); i++) {
                String parentSpid = organizations.get(i).getParentId();
                ConcurrentHashMap<String, WebSocketProcess> concurrentMapParent = concurrentHashMap.get(parentSpid);
                log.info("webSocketProcess-concurrentMapParent:{}",JSONObject.toJSONString(concurrentMapParent));
                if (concurrentMapParent!=null)concurrentMapParents.putAll(concurrentMapParent);
                log.info("webSocketProcess-concurrentMapParents:{}",JSONObject.toJSONString(concurrentMapParents));
            }
        }
        ConcurrentHashMap<String, WebSocketProcess> concurrentMap = concurrentHashMap.get(spId);
        if (concurrentMap==null)concurrentMap=new ConcurrentHashMap<>();
        if (concurrentMapParents!=null)concurrentMap.putAll(concurrentMapParents);
        if (concurrentMap.isEmpty()){
            log.error("webSocketProcess-sendMessage：concurrentHashMap={}"
                    ,JSONObject.toJSONString(concurrentHashMap));
            return;
        }
        log.info("webSocketProcess-sendMessage：WebSocketProcess-concurrentMap={}"
                ,JSONObject.toJSONString(concurrentHashMap));
        concurrentMap.forEach((s, webSocketProcess) -> {
            if (!ObjectUtils.isEmpty(webSocketProcess)) {
                //当客户端是Open状态时，才能发送消息
                if (webSocketProcess.session.isOpen()) {
                    try {
                        webSocketProcess.session.getBasicRemote().sendText(message);
                    } catch (IOException e) {
                        log.error("sendMessage-error:{}",e);
                    }
                } else {
                    log.error("WebSocketProcess：websocket session={} is closed(会话关闭) ", spId);
                }
            }
        });
    }

    //统一入口
    public  void redisTopicSendMsg(String spId, String message) {
        log.info("redisTopicSendMsg：spId={},message={}",spId,message);
        redisTopicSendTemplate.sendMsg(Constants.TOPIC_WEBSOCKET,message+";;"+spId);
        redisTopicSendTemplate.sendMsg(Constants.TOPIC_USER_WEBSOCKET,message+";;"+spId);
        if (checkIsSendDpWs(message)){
            redisTopicSendTemplate.sendMsg(Constants.TOPIC_DP_WEBSOCKET, message+";;"+spId);
        }

    }

    /**
     * 检查哪些消息推送需要通知集团或区域大屏
     * @param message
     * @return
     */
    private boolean checkIsSendDpWs(String message){
        boolean flag = true;
        if(StringUtils.isEmpty(message)){
            return flag;
        }
        JSONObject jsonObject;
        try {
            jsonObject = JSONObject.parseObject(message);
            String notNotifyReasons = "Broken,BrokenRecover,ManualBrokenRecover,PowerOff,ManualPowerOff,PowerOn,ManualPowerOn,WarnStrategy,DeviceCycOff";
            List<String> notNotifyReasonList = Arrays.asList(notNotifyReasons.split(","));
            if( null!=jsonObject && !jsonObject.isEmpty() && jsonObject.containsKey("notifyReason") &&
                    null!=jsonObject.get("notifyReason") && notNotifyReasonList.contains(jsonObject.getString("notifyReason"))){
                flag = false;
            }
        }catch (Exception e){
            log.error("解析message出错",e);
        }
        return flag;
    }
}